package nl.unimaas.micc.umsnooker.control.ui.controller;

import java.util.Collections;
import java.util.Set;

import nl.unimaas.micc.umsnooker.domain.BilliardBall;
import nl.unimaas.micc.umsnooker.domain.Tile;
import nl.unimaas.micc.umsnooker.gameflow.GamePhase;
import nl.unimaas.micc.umsnooker.gameflow.GameState;
import nl.unimaas.micc.umsnooker.gameflow.phases.SimulationPhase;
import nl.unimaas.micc.umsnooker.presentation.SnookerTable3D;
import nl.unimaas.micc.umsnooker.presentation.TablePresentation;
import nl.unimaas.micc.umsnooker.simulation.EventHandler;
import nl.unimaas.micc.umsnooker.simulation.PrescheduledSimulation;
import nl.unimaas.micc.umsnooker.simulation.Simulation;
import nl.unimaas.micc.umsnooker.simulation.event.BallCollision;
import nl.unimaas.micc.umsnooker.simulation.event.Event;
import nl.unimaas.micc.umsnooker.simulation.event.LeaveTileEvent;

import com.jme.input.ChaseCamera;
import com.jme.input.InputHandler;
import com.jme.input.MouseInput;
import com.jme.input.action.InputActionEvent;
import com.jme.input.action.MouseInputAction;
import com.jme.scene.Node;

public class SimulationControl extends InputHandler
{
	private Simulation simulation;
	private GamePhase phase;
	private GameState state;
	private TablePresentation presentation;

	public SimulationControl(final TablePresentation presentation, SimulationPhase phase, final GameState state)
	{
		this.simulation = phase.getSimulation();
		this.phase = phase;
		this.state = state;
		this.presentation = presentation;
		presentation.showShotVisualization(false);
		this.setTilesInPresentation();

		class SimulationMouseInput extends MouseInputAction
		{
			private boolean skipping = false;
			private boolean resumed = false;

			@Override
			public void performAction(InputActionEvent evt)
			{
				if (MouseInput.get().isButtonDown(2) && simulation.isPaused() && (!resumed))
				{
					simulation.resume();
					resumed = true;
				}
				else if (!MouseInput.get().isButtonDown(2) && resumed)
				{
					resumed = false;
				}
				if (MouseInput.get().isButtonDown(1) && !skipping)
				{
					skipping = true;
					simulation.finish();
					for (BilliardBall b : state.getBalls())
					{
						simulation.getBall(b);
						presentation.updateBall(b);
					}
				}
				else
				{
					skipping = false;
				}
			}
		}

		simulation.addEventHandler(new EventHandler()
		{
			@Override
			public void handle(Event e)
			{
				if (e instanceof BallCollision)
				{
					// ((SnookerTable3D)
					// presentation).makeShine(e.getBallKeys());
				}

			}
		});
		

		this.addAction(new SimulationMouseInput());
	}

	@Override
	public void update(float time)
	{
		super.update(time);
		if (simulation.isReady())
		{
			if (simulation.hasNextEvent())
			{
				if (simulation instanceof PrescheduledSimulation)
				{
					Event nextPocketCollision = ((PrescheduledSimulation)simulation).getNextPocketCollision();
					if (nextPocketCollision != null && (nextPocketCollision.getTime() - simulation.getCurrentTime()) < 1.0f)
					{
						Set<BilliardBall> balls = nextPocketCollision.getBallKeys();
						BilliardBall ball = (BilliardBall) balls.toArray()[0];
						Node ballNode = presentation.getBallNode(ball);
						ChaseCamera cam = (ChaseCamera) presentation.getCameraControl();
						cam.setTarget(ballNode);
						time = time / 10;
					}

					else
					{
						ChaseCamera cam = (ChaseCamera) presentation.getCameraControl();
						cam.setTarget(presentation.getTableNode());
					}
				}
				simulation.advanceTime(time);

				for (BilliardBall b : state.getBalls())
				{
					simulation.getBall(b);
					presentation.updateBall(b);

				}
				presentation.updateTileVisualization(state.getBalls());
			}
			else
			{
				phase.finish();
			}
		}
	}

	private void setTilesInPresentation()
	{
		Tile[][] tiles = simulation.getTiles();
		Tile[][] tilesClone = new Tile[tiles.length][tiles[0].length];

		for (int i = 0; i < tiles.length; i++)
		{
			for (int j = 0; j < tiles[0].length; j++)
			{
				tilesClone[i][j] = (Tile) tiles[i][j].clone();
				tilesClone[i][j].setFromX(tilesClone[i][j].getFromX() - (0.5f * state.getTable().getWidth()));
				tilesClone[i][j].setFromY(tilesClone[i][j].getFromY() - (0.5f * state.getTable().getLength()));
				tilesClone[i][j].setToX(tilesClone[i][j].getToX() - (0.5f * state.getTable().getWidth()));
				tilesClone[i][j].setToY(tilesClone[i][j].getToY() - (0.5f * state.getTable().getLength()));

			}
		}
		SnookerTable3D table = (SnookerTable3D) presentation;
		table.setTiles(tilesClone);
	}
}
